package com.tien.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import javax.persistence.Entity;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.exception.DataException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Component;

import com.tien.dao.BaseDao;


/**
 * @ClassName: BaseDAOImpl
 * @author xt40919
 * @version Create Time：Mar 29, 2011 2:10:09 PM
 */
@Component
public class BaseDaoImpl<T,ID extends Serializable>  implements BaseDao<T,ID> {
   
    private HibernateTemplate hibernateTemplate;
    @Autowired
    public void setHibernateTemplate(@Qualifier("sessionFactory")SessionFactory sessionFactory){
        this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    }

    public T saveEntity(T entity) throws DataAccessException{
        hibernateTemplate.save(entity);
        return entity;
    }
    public void updateEntity(T entity) throws DataAccessException {
            hibernateTemplate.update(entity);
    }
    
    public T mergeEntity(T entity) throws DataAccessException {
        return (T)hibernateTemplate.merge(entity);
    }
    
    public T findById(Class<T> clazz, ID id) throws DataAccessException {
        return (T)hibernateTemplate.get(clazz, id);
    }
    public List<T> getEntitiesByHQL(String hql)  throws DataAccessException{
        return this.getEntitiesByHQL(hql, null, null, null);
    }
    public List<T> getEntitiesByHQL(String hql, Integer start, Integer limit) throws DataAccessException {
        return this.getEntitiesByHQL(hql, start, limit, null);
    }
    public List<T> getEntitiesByHQL(String hql, Object... argValues) throws DataAccessException {
        return this.getEntitiesByHQL(hql, null, null, argValues);
    }
    @SuppressWarnings("unchecked")
    public List<T> getEntitiesByHQL(final String hql,final Integer start,final    Integer limit,final Object... argValues) throws DataAccessException {
        return    hibernateTemplate.executeFind(new HibernateCallback(){
            public Object doInHibernate(Session session)
                    throws DataAccessException {
                Query query=session.createQuery(hql);
                if(argValues!=null){
                    for(int i=0;i<argValues.length;i++){
                        query.setParameter(i, argValues[i]);
                    }
                }
                if(start!=null){
                    query.setFirstResult(start);
                }
                if(limit!=null){
                    query.setMaxResults(limit);
                }
                return query.list();
            }
           
        });
    }
    
    public List<T> getEntitiesBySQL(String sql, Class[] classes) throws DataAccessException {
        return this.getEntitiesBySQL(sql, classes, null, null, null);
    }
    public List<T> getEntitiesBySQL(String sql, Class[] classes, Integer start,
            Integer limit)throws DataAccessException {
        return this.getEntitiesBySQL(sql, classes, null, start, limit);
    }
    public List<T> getEntitiesBySQL(String sql, Class[] classes, Object... argValues) throws DataAccessException{
        return this.getEntitiesBySQL(sql, classes, null, null, argValues);
    }
    @SuppressWarnings("unchecked")
    public List<T> getEntitiesBySQL(final String sql,final Class[] classes,final Integer start,final Integer limit,final Object... argValues)  throws DataAccessException{
         return    hibernateTemplate.executeFind(new HibernateCallback(){

                public Object doInHibernate(Session session)
                        throws DataAccessException {
                    SQLQuery query=session.createSQLQuery(sql);
                    if(classes!=null){
                        for(Class clazz:classes){
                            query.addEntity(clazz);
                        }
                    }
                    if(argValues!=null){
                        for(int i=0;i<argValues.length;i++){
                            query.setParameter(i, argValues[i]);
                        }
                    }
                    if(start!=null){
                        query.setFirstResult(start);
                    }
                    if(limit!=null){
                        query.setMaxResults(limit);
                    }
                    return query.list();
                }
               
               
            });
       
    }
    public Criteria createCriteria(final Class<T> clazz) throws DataAccessException{
        // TODO Auto-generated method stub
        return (Criteria)hibernateTemplate.execute(new HibernateCallback(){
            public Object doInHibernate(Session session)
                    throws DataAccessException {
                return session.createCriteria(clazz);
            }
        });
    }
    public void deleteEntity(T entity) throws DataException{
        hibernateTemplate.delete(entity);
    }
    public void deleteEntities(Collection<T> entities) throws DataAccessException {
        hibernateTemplate.deleteAll(entities);
    }
    public void deleteEntityById(Class<T> clazz,ID id) throws DataAccessException{
        T entity=this.findById(clazz, id);
        this.deleteEntity(entity);
    }
    @SuppressWarnings("unchecked")
    public Criteria createDetachedCriteria(final DetachedCriteria detachedCriteria) throws DataAccessException{
        // TODO Auto-generated method stub
        return (Criteria)hibernateTemplate.execute(new HibernateCallback(){
            public Object doInHibernate(Session session)
                    throws DataAccessException {
                return detachedCriteria.getExecutableCriteria(session);
            }
        });
    }
  

    public Long countEntitiesByHQL(String hql){
        return this.countEntitiesByHQL(hql,null);
    }
    
    @SuppressWarnings("unchecked")
    public Long countEntitiesByHQL(final String hql,final Object... argValues){
        return    (Long) hibernateTemplate.execute(new HibernateCallback(){
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query=session.createQuery(hql);
                if(argValues!=null){
                    for(int i=0;i<argValues.length;i++){
                        query.setParameter(i, argValues[i]);
                    }
                }
                return query.uniqueResult();
            }
        });
    }
    
    @SuppressWarnings("unchecked")
    public Object findEntityByHQL(final String hql,final Object... argValues){
        return hibernateTemplate.execute(new HibernateCallback(){

            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query=session.createQuery(hql);
                if(argValues!=null){
                    for(int i=0;i<argValues.length;i++){
                        query.setParameter(i, argValues[i]);
                    }
                }
                return query.uniqueResult();
            }
           
        });
    }
    @SuppressWarnings("unchecked")
    public Object findEntityBySQL(final String sql,final Class[] classes,final Object... argValues){
        return hibernateTemplate.execute(new HibernateCallback(){

            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                SQLQuery query=session.createSQLQuery(sql);
                if(classes!=null){
                    for(Class classzz:classes){
                        query.addEntity(classzz);
                    }
                }
                if(argValues!=null){
                    for(int i=0;i<argValues.length;i++){
                        query.setParameter(i, argValues[i]);
                    }
                }
                return query.uniqueResult();
            }
           
        });
       
    }
    public Object findEntityBySQL(String sql,Object... argValues){
        return this.findEntityBySQL(sql,null,argValues);
    }
    public Long countEntitiesBySQL(final String sql,final Class[] classes){
        return this.countEntitiesBySQL(sql,classes,null);
    }
    @SuppressWarnings("unchecked")
    public Long countEntitiesBySQL(final String sql,final Class[] classes,final Object... argValues){
        return (Long)hibernateTemplate.execute(new HibernateCallback(){

            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                SQLQuery query=session.createSQLQuery(sql);
                if(classes!=null){
                    for(Class classzz:classes){
                        query.addEntity(classzz);
                    }
                }
                if(argValues!=null){
                    for(int i=0;i<argValues.length;i++){
                        query.setParameter(i, argValues[i]);
                    }
                }
                return query.uniqueResult();
            }
           
        });
    }

}
